package peace.gui.dnd
{
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;

[Event(name="startDrag", type="peace.gui.dnd.DragEvent")] 
[Event(name="stopDrag", type="peace.gui.dnd.DragEvent")] 
[Event(name="move", type="peace.gui.dnd.DragEvent")] 
/**
 * Слушатель ДНД-события (нажали-потаскали-отпустили) на своей территории <br>
 * Сам не таскается 
 */
public class DragListener extends Sprite
{
	/**
	 * точка начала текущего/последнего таскания 
	 */	
	public var startDragPoint:Point = new Point();
	/**
	 * 
	 */
	public var dragged:Boolean = false;
	/**
	 * альтернативный "стабильный" родитель, на mouseX,Y которого завязаны события
	 */	
	public var coordinateSpaceParent:DisplayObjectContainer;

	private var _enabled:Boolean = true;
	/**
	 * 
	 * @return 
	 * 
	 */
	public function get enabled():Boolean {return _enabled}
	/**
	 * 
	 * @param b Boolean
	 * 
	 */
	public function set enabled(b:Boolean):void 
	{
		if (b)
		{
			addEventListener(MouseEvent.MOUSE_DOWN, onPress, false,0,true);
		}
		else
		{
			removeEventListener(MouseEvent.MOUSE_DOWN, onPress);
			onRelease(null);
		}
		
		_enabled = b;
	}
	/**
	 * 
	 * @param coordinateSpaceParent альтернативный "стабильный" родитель, на mouseX,Y которого завязаны события
	 * 
	 */	
	public function DragListener (coordinateSpaceParent:DisplayObjectContainer = null)
	{
		super();
		this.coordinateSpaceParent = coordinateSpaceParent;
		enabled = true;
	}
	/**
	 * Начинаем слушать таскание
	 *  
	 * @param startDragPoint Point
	 * @param fireEvent слать ли DragEvent.START_DRAG
	 * 
	 */	
	public function beginDrag (startDragPoint:Point = null, fireEvent:Boolean = false):void
	{
		if (startDragPoint) this.startDragPoint = startDragPoint;
		
		dragged = true;
		
		stage.addEventListener(MouseEvent.MOUSE_UP, onRelease, false, 0, true);
		stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove, false, 0, true);
		
		// кидаем событие без параметров ибо их не может быть
		// в слушателе ДНД нам интересно только знать дельту с начала перемещения
		if (fireEvent)
		{
			dispatchEvent(new DragEvent(DragEvent.START_DRAG)); 
		}
	}
	/**
	 * Перестали слушать таскание
	 * 
	 */	
	public function endDrag ():void
	{
		if (stage)
		{
			stage.removeEventListener(MouseEvent.MOUSE_UP, onRelease);
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
		}
		dragged = false;
	}
	/**
	 * 
	 * @param e
	 * 
	 */	
	private function onPress (e:MouseEvent):void
	{
		startDragPoint.x = parent.mouseX;
		startDragPoint.y = parent.mouseY;
		
		beginDrag(null, true);
	}
	/**
	 * 
	 * @param e
	 * 
	 */
	private function onRelease (e:MouseEvent):void
	{
		if (_enabled && dragged && parent)
		{
			dispatchEvent(new DragEvent(DragEvent.STOP_DRAG, 
				new Point(parent.mouseX - startDragPoint.x, parent.mouseY - startDragPoint.y), e.ctrlKey, e.shiftKey)); 
		}

		endDrag();
	}
	/**
	 * 
	 * @param e
	 * 
	 */
	private function onMouseMove (e:MouseEvent):void
	{
		if (_enabled && dragged && parent)
		{
			// шлем дельту
			dispatchEvent(new DragEvent(DragEvent.MOVE, 
				new Point(parent.mouseX - startDragPoint.x, parent.mouseY - startDragPoint.y), e.ctrlKey, e.shiftKey));
		}
	}
	/**
	 * 
	 * @return DisplayObjectContainer
	 * 
	 */	
	override public function get parent():DisplayObjectContainer
	{
		return coordinateSpaceParent || super.parent;
	}
	
}
}